﻿#include "Loadshader.h"
#include <stdlib.h>
using namespace Dengine;
using namespace std;
#define NULLPTR ((char *)0)

Loadshader::Loadshader() :error(NULLPTR)
{
	fprintf(stdout, "Shader constructor\n");
}

void Loadshader::LoadFromFile(const char* file, type shader)
{
	fprintf(stdout, "Loading shader - %s\n", file);
	if (program == 0)program = glCreateProgram();
	ifstream is(file);
	if (is)
	{
		is.seekg(0, is.end);
		int length = is.tellg();
		is.seekg(0, is.beg);

		char* buffer = new char[length];
		is.read(buffer, length);
		CompileShader(buffer, length, shader);
		free(buffer);
	}
	else
		fprintf(stdout, "Could not find %s\n", file);
}

void Loadshader::CompileShader(const char* buffer, const GLint buffer_length, type shader)
{
	GLuint shader_type;
	switch (shader)
	{
	case type::FRAGMENT_SHADER: shader_type = glCreateShader(GL_FRAGMENT_SHADER);   break;
	case type::VERTEX_SHADER: shader_type = glCreateShader(GL_VERTEX_SHADER);   break;
	}

	//We specify length of buffer because it not ends into trailing garbage. Otherwise we would get compile error.
	glShaderSource(shader_type, 1, &buffer, &buffer_length); //get the shader source
	glCompileShader(shader_type); //compile shader
	if (!CheckCompileError(shader_type))
		LogError();

	glAttachShader(program, shader_type);
	glLinkProgram(program);
	if (!LinkingError())
	{
		LogError();
		fprintf(stdout, "Opps, something wrong with linking\n");
	}


	//Always detach shaders after a successful link.
	glDeleteShader(shader_type);
}

bool Loadshader::CheckCompileError(GLuint Shader_type)
{
	GLint success = 0;
	glGetShaderiv(Shader_type, GL_COMPILE_STATUS, &success);
	if (success == GL_FALSE)
	{
		GLint logSize = 0;
		glGetShaderiv(Shader_type, GL_INFO_LOG_LENGTH, &logSize);
		error = (char*)malloc(logSize);
		glGetShaderInfoLog(Shader_type, logSize, NULL, error);
		return false;
	}
	else return true;

}

bool Loadshader::LinkingError()
{
	GLint isLinked = 0;
	glGetProgramiv(program, GL_LINK_STATUS, (int *)&isLinked);
	if (isLinked == GL_FALSE)
	{
		GLint maxLength = 0;
		glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);

		error = (char*)malloc(maxLength);
		glGetProgramInfoLog(program, maxLength, &maxLength, error);
		return false;
	}
	return true;
}
Loadshader::~Loadshader()
{
	fprintf(stdout, "Shader was destroyed\n");
	free(error);
	glDeleteProgram(program);
}
